package com.sec.etech.ism.util;

import com.alibaba.fastjson.JSONObject;
import com.sec.etech.ism.constant.SignatureConstant;
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Set;

//https://www.jb51.net/article/214770.htm
public class SignatureUtil {

    /**
     * 根据请求参数中的key排序，并将对应的value转换为字符串
     *
     * @param requestParams 请求参数
     * @return String 返回转换后的结果
     */
    public static String sortToStr(JSONObject requestParams) {
        // 对参数进行排序
        Set<String> paramKeys = requestParams.keySet();
        String[] sortParamKeys = new String[paramKeys.size()];
        Arrays.sort(paramKeys.toArray(sortParamKeys));
        StringBuffer paramValueStr = new StringBuffer();

        // 将请求参数json转换为字符串，用于签名
        for (String paramKey : sortParamKeys) {
            if (SignatureConstant.SIGNATURE_CREATED.equals(paramKey)) {
                paramValueStr.append(SignatureConstant.CONCAT_KEY).append(requestParams.getLong(paramKey));
                continue;
            }
            paramValueStr.append(SignatureConstant.CONCAT_KEY).append(requestParams.get(paramKey).toString());
        }
        // 删除头部的连接符
        String paramValue = null;
        if (paramValueStr.toString().startsWith(SignatureConstant.CONCAT_KEY) && paramValueStr.length() >= 1) {
            paramValue = paramValueStr.substring(1);
        }
        return paramValue;
    }

    /**
     * 通过秘钥对字符串进行签名
     *
     * @param params 需要签名的字符串
     * @param secret 签名秘钥（分配的系统秘钥）
     * @param keyMac  MAC算法可选以下多种算法：HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
     * @return 返回签名后的结果
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     */
    public static String signature(String params, String secret, String keyMac) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        Mac hmac = Mac.getInstance(keyMac);
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes("UTF-8"), keyMac);
        hmac.init(secretKey);
        return Base64.encodeBase64String(hmac.doFinal(params.getBytes("UTF-8")));

    }

    /**
     * 构建接口请求体的内容
     * @param inputParams 参数内容
     * @param appSecrete 签名秘钥（分配的系统秘钥）
     * @param timeStamp 时间戳
     * @param keyMac  MAC算法可选以下多种算法：HmacMD5/HmacSHA1/HmacSHA256/HmacSHA384/HmacSHA512
     * @return 返回调用接口的请求体内容
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     */
    public static JSONObject buildRequestParamsByTimeStamp(JSONObject inputParams, String appSecrete, Long timeStamp, String keyMac)
            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        // 时间戳
        if (null == timeStamp || timeStamp == 0l) {
            timeStamp = System.currentTimeMillis() / 1000;
        }
        //System.out.printf("   时间戳:%s \n", timeStamp);
        // 接口请求参数
        JSONObject requestParams = new JSONObject();
        requestParams.put(SignatureConstant.INPUT_PARAMS, inputParams);

        requestParams.put(SignatureConstant.SIGNATURE_CREATED, timeStamp);
        //将请求参数转换为String,用于签名使用
        String requestParamsStr = SignatureUtil.sortToStr(requestParams);
        //System.out.printf("1、需要签名的字符串:%s \n", requestParamsStr.replace(SignatureConstant.CONCAT_KEY, "\n"));
        //将请求参数进行签名
        String signature = SignatureUtil.signature(requestParamsStr, appSecrete, keyMac);
        //System.out.printf("2、参数签名结果:%s \n", signature);
        requestParams.put(SignatureConstant.SIGNATURE_PARAMS, signature);
        //System.out.printf("3、请求参数格式如下:%s \n", requestParams.toJSONString());
        return requestParams;
    }

    /**
     * 检查签名是否一致
     * @param requestParams 带签名的请求参数
     * @param appSecrete 秘钥
     * @param keyMac MAC算法
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws UnsupportedEncodingException
     */
    public static boolean checkSignature(JSONObject requestParams, String appSecrete, String keyMac)
            throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        // 接口请求参数
        JSONObject requestTmp = new JSONObject();
        requestTmp.put(SignatureConstant.INPUT_PARAMS, requestParams.get(SignatureConstant.INPUT_PARAMS));

        requestTmp.put(SignatureConstant.SIGNATURE_CREATED, requestParams.get(SignatureConstant.SIGNATURE_CREATED));
        //将请求参数转换为String,用于签名使用
        String requestParamsStr = SignatureUtil.sortToStr(requestTmp);
        //将请求参数进行签名
        String signature = SignatureUtil.signature(requestParamsStr, appSecrete, keyMac);
        return requestParams.getString(SignatureConstant.SIGNATURE_PARAMS).equals(signature);
    }
}
